#include "Common.h"

Object::Object() : m_flyspeed(7.0f), m_runspeed(7.0f), m_backrunspeed(4.5f), m_swimspeed(4.722222f),
m_backswimspeed(2.5f), m_backflyspeed(2.5f), m_walkspeed(2.5f), m_turnspeed(3.14f), m_update(false),
m_maphandler(NULL), m_moved(false), m_mapcell(NULL), m_speedchanged(0)
{
}

Object::~Object()
{
	delete [] m_ui32values;
}

void Object::PackGuid(RealmPacket* pOut)
{
	if(!pOut)
		return;
	ui64 guid = GetGUID();
	ui8 mask = 0;
	ui8 fields[9] = { 0 };
	ui8* ptr = (ui8*)&guid;
	for(ui32 i = 1; i < 9; ++i)
	{
		fields[i] = *(ptr + i - 1);
		mask |= (1 << (i - 1));
	}
	fields[0] = mask;
	pOut->Append(fields, 9);
}

void Object::SetUI32Value(ui32 index, ui32 value)
{
		if(index >= m_fieldcount)
			return;
		if(value == m_ui32values[index])
			return;
		m_ui32values[index] = value;
		m_updatemask.SetBit(index); // This index needs to be updated
		if(m_maphandler)
		{
			m_update = true;
			m_maphandler->AddUpdateObject(this);
		}
}

void Object::SetFloatValue(ui32 index, float value)
{
		if(index >= m_fieldcount) // prevent segmentation fault ;D
			return;
		if(value == m_floatvalues[index]) // Dont waste time to send an updatepacket if we dont actually change!
			return;
		m_floatvalues[index] = value;
		m_updatemask.SetBit(index); // This index needs to be updated
		if(m_maphandler) // As items or objects not in world actually have no maphandler this is very important
			m_maphandler->AddUpdateObject(this);
		m_update = true;
}

void Object::SetFlag(ui32 index, ui32 value)
{
		if(index >= m_fieldcount) // prevent segmentation fault ;D
			return;
		m_ui32values[index] |= value; // Add the new flag via OR
		m_updatemask.SetBit(index); // This index needs to be updated
		if(m_maphandler) // As items or objects not in world actually have no maphandler this is very important
			m_maphandler->AddUpdateObject(this);
		m_update = true;
}

void Object::RemoveFlag(ui32 index, ui32 value)
{
	if(index >= m_fieldcount)
		return;
	m_ui32values[index] &= ~value;
	m_updatemask.SetBit(index);
	if(m_maphandler)
		m_maphandler->AddUpdateObject(this);
	m_update = true;
}

void Object::SetByte(ui32 index, ui32 position, ui8 value)
{
	ui8* v =&((ui8*)m_ui32values)[index * 4 + position]; // Get the address of our byte
	*v = value; // change it
	m_updatemask.SetBit(index); // and mark the whole index to be updated
	if(m_maphandler)
			m_maphandler->AddUpdateObject(this);
	m_update = true;
}

ui8 Object::GetByte(ui32 index, ui8 position)
{
	return *(((ui8*)m_ui32values) + (4 * index + position));
}

void Object::UpdateInRangeSet(RealmPacket* data, bool Creation)
{
	ObjectInRangeSet::iterator itr = m_inrangeset.begin();
	ObjectInRangeSet::iterator end = m_inrangeset.end();
	for( ; itr != m_inrangeset.end(); ++itr)
	{
		if((*itr)->GetTypeId() == TYPEID_PLAYER)
			if(Creation)
				((Player*)(*itr))->PushCreationData(data);
			else
				((Player*)(*itr))->PushUpdateData(data);
	}
}

void Object::BuildMoveUpdates(RealmPacket* buffer, ui32 flags)
{
	RealmPacket& data = *buffer;
	if(flags & 0x20) // 0x20 stands for "living object"
	{
		data << ui32(0) << ui16(0) << ui32(GetTickCount());
	}

	if(flags & 0x40) // 0x40 stands for "has position"
	{
		data << m_position._x << m_position._y << m_position._z;
		data << m_orientation;
	}
	if(flags & 0x20)
	{
		data<< ui32(0);
		data << m_walkspeed << m_runspeed << m_backrunspeed << m_swimspeed << m_backswimspeed << m_flyspeed << m_backflyspeed;
		data << m_turnspeed << float(7.0);
	}
	if(flags & 0x08) // 0x08 means highguid and lowguid
	{
		data << GetUI32Value(OBJECT_FIELD_GUID);
		data << GetUI32Value(OBJECT_FIELD_GUID + 4);
	}
	else if(flags & 0x10) // 0x10 means only lowguid
		data << GetUI32Value(OBJECT_FIELD_GUID);
}

void Object::BuildCreation(Player* target, RealmPacket* buffer)
{
	int a = 0;
	for(ui32 i = 0; i < m_fieldcount; ++i)
		if(m_ui32values[i])
		{
			++a;
			m_updatemask.SetBit(i);
		}
	RealmPacket& data = *buffer;
	ui8 type = 0;
	if(target == this)
		type = 3;
	else
		type = 2;
	data << type;
	data << m_guid;
	data << ui8(m_typeid);
	ui32 flags = 0;
	switch(m_typeid)
	{
	case TYPEID_ITEM:
	case TYPEID_CONTAINER:
		flags = 0x10;
		break;

	case TYPEID_UNIT:
	case TYPEID_PLAYER:
		flags = 0x70;
		break;

	case TYPEID_GAMEOBJECT:
	case TYPEID_CORPSE:
	case TYPEID_DYNAMICOBJECT:
		flags = 0x58;
		break;
	}
	if(target == this)
		flags |= 0x01;


	data << ui16(flags);
	BuildMoveUpdates(buffer, flags);
	BuildValuesUpdate(buffer);
}

void Object::BuildValuesUpdate(RealmPacket* buffer)
{
	RealmPacket& data = *buffer;
	ui32 bc;
	ui32 values_count;
	if(m_fieldcount > (2 * 0x20))
	{
		bc = m_updatemask.GetUpdateBlockCount();
		values_count = min(bc * 32,  m_fieldcount);
	}
	else
	{
		bc = m_updatemask.GetBlockCount();
		values_count = m_fieldcount;
	}

	data << (ui8)bc;
	data.Append((ui8*)m_updatemask.GetMask(), bc*4);
	for( ui32 index = 0; index < values_count; index ++ )
	{
		if( m_updatemask.GetBit( index ) )
		{
			data << m_ui32values[ index ];
		}
	}
	m_updatemask.Clear();
}

void Object::BuildFieldUpdates(RealmPacket* buffer)
{
	RealmPacket& data = *buffer;
	data << ui8(0);
	data << m_guid;
	BuildValuesUpdate(buffer);
}

void Object::AddInRangeObject(Object* obj)
{
	m_inrangeset.insert(obj);
	if(obj->GetTypeId() == TYPEID_PLAYER)
		m_inrangeplayers.insert((Player*)obj);
}

void Object::SendToSet(RealmPacket& data)
{
	set<Object*>::iterator itr = m_inrangeset.begin();
	for( ; itr != m_inrangeset.end(); ++itr)
		if((*itr)->GetTypeId() == TYPEID_PLAYER)
			((Player*)(*itr))->GetSession()->SendPacket(&data);
	if(GetTypeId() == TYPEID_PLAYER)
		((Player*)this)->GetSession()->SendPacket(&data);
}